﻿using System;
using System.Collections.Generic;
using System.Text;
using HttpServer;
using System.Collections.Specialized;
using System.IO;
using System.Web;
using UOL.PagSeguro.TestServer.Properties;
using System.Globalization;

namespace UOL.PagSeguro.TestServer {
    public class PagSeguroServer : IPagSeguroServer {

        private static readonly System.Net.IPAddress ADDRESS = System.Net.IPAddress.Any;
        private static readonly string ENCODING = "iso-8859-1";

        private HttpListener _listener;
        private bool _started;

        public PagSeguroServer() {
            this._listener = new HttpListener(ADDRESS, int.Parse(Settings.Default.PORTA));
            this._listener.RequestHandler += this.OnRequest;
            this._started = false;
        }

        private void OnRequest(IHttpClientContext context, IHttpRequest request) {
            Encoding encoding = Encoding.GetEncoding(PagSeguroServer.ENCODING);
            
            //Página solicitada ao servidor
            string requestedPage = request.Uri.AbsolutePath;

            //Conteúdo da Solicitação
            string content = string.Empty;

            using (StreamReader reader = new StreamReader(request.Body, encoding)) {
                content = reader.ReadToEnd();
                reader.Close();
            }

            //Processamento da Resposta
            byte[] responseBody = encoding.GetBytes(string.Format("<html><head><script language=\"javascript\">window.location=\"{0}\";</script></head><body></body></html>", Settings.Default.URL_Retorno));
            IHttpResponse response = new HttpServer.HttpResponse(context, request);

            if ((requestedPage.Equals(Resources.URL_Test_Venda, StringComparison.InvariantCultureIgnoreCase) || requestedPage.Equals(Resources.URL_Test_Venda_Antiga, StringComparison.InvariantCultureIgnoreCase)) && content.Length > 0) {
                if (this.OnVendaReceived != null) {
                    NameValueCollection nvc = new NameValueCollection();
                    foreach (string token in content.Split('&')) {
                        string[] pair = token.Split('=');
                        nvc.Add(HttpUtility.UrlDecode(pair[0], encoding), HttpUtility.UrlDecode(pair[1], encoding));
                    }
                    try {
                        VendaPagSeguro venda = this.CreateVenda(nvc);
                        this.OnVendaReceived(venda);
                    } catch {
                        this.OnServerResponse("Houve uma falha ao decodificar a venda recebida. Verifique os parâmetros enviados e tente novamente.");
                    }
                }
            } else if (requestedPage.Equals(Resources.URL_Test_NPI, StringComparison.InvariantCultureIgnoreCase) || requestedPage.Equals(Resources.URL_Test_NPI_Antiga, StringComparison.InvariantCultureIgnoreCase)) {
                responseBody = encoding.GetBytes("VERIFICADO");
            }
            response.Body.Write(responseBody, 0, responseBody.Length);
            response.Send();
        }

        public void ProcessarRetornoAutomatico(string querystring) {
            byte[] bytedata = Encoding.GetEncoding(PagSeguroServer.ENCODING).GetBytes(querystring);

            try {
                System.Net.HttpWebRequest request = (System.Net.HttpWebRequest) System.Net.HttpWebRequest.Create(Settings.Default.URL_Retorno);
                request.Method = System.Net.WebRequestMethods.Http.Post;
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = bytedata.Length;

                using (Stream requestStream = request.GetRequestStream()) {
                    requestStream.Write(bytedata, 0, bytedata.Length);
                    requestStream.Close();
                }

                request.GetResponse();
            }catch {
                this.OnServerResponse("Houve uma falha ao processar o retorno automático. Verifique sua URL de retorno.");
            }
        }

        private VendaPagSeguro CreateVenda(NameValueCollection nvc) {
            VendaPagSeguro venda = new VendaPagSeguro(nvc["email_cobranca"]);
            venda.CodigoReferencia = nvc["ref_transacao"];
            venda.Moeda = nvc["moeda"];
            venda.TipoCarrinho = nvc["tipo"].ToUpper().Equals("CP") ? TipoCarrinho.CarrinhoProprio : TipoCarrinho.CarrinhoPagSeguro;

            int extras = 0;
            int.TryParse(nvc["extras"], out extras);
            venda.Extras = extras / 100.00;

            switch (nvc["tipo_frete"]) {
                case "SD":
                    venda.TipoFrete = TipoFreteVenda.Sedex;
                    break;
                case "EN":
                    venda.TipoFrete = TipoFreteVenda.PAC;
                    break;
                default:
                    venda.TipoFrete = TipoFreteVenda.DefinidoPeloCliente;
                    break;
            }

            //Cliente
            venda.Cliente = new Cliente();
            venda.Cliente.Nome = nvc["cliente_nome"];
            venda.Cliente.Cep = nvc["cliente_cep"];
            venda.Cliente.Endereco = nvc["cliente_end"];
            venda.Cliente.Numero = nvc["cliente_num"];
            venda.Cliente.ComplementoEndereco = nvc["cliente_compl"];
            venda.Cliente.Bairro = nvc["cliente_bairro"];
            venda.Cliente.Cidade = nvc["cliente_cidade"];
            venda.Cliente.Uf = nvc["cliente_uf"];
            venda.Cliente.Pais = nvc["cliente_pais"];
            if (!string.IsNullOrEmpty(nvc["cliente_ddd"])) {
                venda.Cliente.DDD = int.Parse(nvc["cliente_ddd"]);
            }
            if (!string.IsNullOrEmpty(nvc["cliente_tel"])) {
                venda.Cliente.Telefone = int.Parse(nvc["cliente_tel"]);
            }
            venda.Cliente.Email = nvc["cliente_email"];

            //Produtos
            venda.Produtos = new List<Produto>();
            int productIndex = 1;
            while (!string.IsNullOrEmpty(nvc["item_id_" + productIndex])) {
                Produto produto = new Produto();
                produto.Codigo = nvc["item_id_" + productIndex];
                produto.Descricao = nvc["item_descr_" + productIndex];
                produto.Quantidade = int.Parse(nvc["item_quant_" + productIndex]);
                produto.Valor = int.Parse(nvc["item_valor_" + productIndex]) / 100.00;

                int peso = 0;
                int.TryParse(nvc["item_peso_" + productIndex], out peso);
                produto.Peso = peso;

                int frete = 0;
                int.TryParse(nvc["item_frete_" + productIndex], out frete);
                produto.Frete = frete / 100.00;

                venda.Produtos.Add(produto);
                productIndex++;
            }
            return venda;
        }


        #region IPagSeguroServer Members

        public event OnServerResponseEventHandler OnServerResponse;

        public event OnVendaReceivedEventHandler OnVendaReceived;

        public void Start() {
            this.OnServerResponse("Starting PagSeguro server...");
            this._listener.Start(5);
            this._started = true;
            this.OnServerResponse(string.Format("PagSeguro server is now listening on http://{0}:{1}", ADDRESS.ToString(), int.Parse(Settings.Default.PORTA)));
        }

        public void Stop() {
            this.OnServerResponse("Stopping PagSeguro server...");
            this._listener.Stop();
            this._started = false;
            this.OnServerResponse("PagSeguro stoped");
        }

        public bool IsOnline() {
            return this._started;
        }

        #endregion

        #region IDisposable Members

        public void Dispose() {
            if (this._started) {
                this._listener.Stop();
            }
        }

        #endregion
    }
}
